// BottomMainFramePanel.cs
//
//  Copyright (C) 2008 Jacek Trubłajewicz
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//

using System;
using System.Drawing;
using System.IO;
using Mono.Unix;
using NLog;

namespace wxGadu
{
	public delegate void UserStatusChangeEventHandler(int newStatus);
	
	public class BottomMainFramePanel : wx.Panel
	{
		//static int licznik = 0;
		#region Id
		private enum Id
		{
			descriptionBox,
			statusBitmap,
			contactDescriptionText,
			contactNameText,
			photoBitmap
		}
		#endregion

		#region controls
		private wx.BoxSizer topSizer;
		private wx.TextCtrl contactNameText;
		//private wx.StaticText contactDescriptionText;
		private wx.TextCtrl contactDescriptionText;
		private wx.StaticBitmap photoBitmap;
		private StatusStaticBitmap statusBitmap;
		private wx.ComboBox descriptionBox;
		private wx.Menu statusMenu;
		#endregion

		#region data members
		private MainFrame mainFrame;
#if LOG
		private Logger logger = LogManager.GetCurrentClassLogger();
#endif
		private int visibleUin;
		#endregion
		
		public BottomMainFramePanel(wx.Window parent, MainFrame mainFrame):
			base(parent)
		{
			this.mainFrame = mainFrame;
			
			DoControls();
			DoControlsProperties();
			DoLayout();

			EVT_COMBOBOX((int) Id.descriptionBox, new wx.EventListener(OnDescriptionSelected));
			EVT_TEXT_ENTER((int) Id.descriptionBox, new wx.EventListener(OnNewDescriptionAdded));
			EVT_TEXT((int) Id.descriptionBox, new wx.EventListener(OnDescriptionTextValueChanged));
			EVT_UPDATE_UI((int) FakeId.clearInfoPanel, new wx.EventListener(OnInfoPanelClear));
		} 

		private void DoControls()
		{
			contactNameText = new wx.TextCtrl(this, (int) Id.contactNameText, "",
			                                   wx.Window.wxDefaultPosition, new Size(100, 30),
			                                   wx.TextCtrl.wxTE_MULTILINE|wx.TextCtrl.wxTE_READONLY|wx.TextCtrl.wxNO_BORDER);
			
			contactDescriptionText = new wx.TextCtrl(this, (int) Id.contactDescriptionText,  "", 
			                                           wx.Window.wxDefaultPosition, new Size(100, 30),
			                                           wx.TextCtrl.wxTE_MULTILINE|wx.TextCtrl.wxTE_READONLY|wx.TextCtrl.wxNO_BORDER);
			
			photoBitmap = new wx.StaticBitmap(this, (int) Id.photoBitmap, mainFrame.ImageMgr[ImageManager.EMPTY],
			                                  wx.Window.wxDefaultPosition, new Size(80, 80));

			statusBitmap = new StatusStaticBitmap(this, (int) Id.statusBitmap, 
                                   mainFrame.ImageMgr.StatusBitmaps[StatusConstans.offline],
                                   wx.Window.wxDefaultPosition, new Size(16, 18), 
                                   wx.Window.wxNO_BORDER);

			descriptionBox = new wx.ComboBox(this, (int) Id.descriptionBox);
		}

		private void DoControlsProperties()
		{
			statusBitmap.BitmapClicked += new StatusBitmapClickEventHandler(OnStatusBitmapClicked);

			if (statusMenu == null)
			{
				statusMenu = new wx.Menu();
	
				wx.MenuItem online = new wx.MenuItem();
				online.Text = ContactManager.StatusToString(StatusConstans.online);
				online.Bitmap = mainFrame.ImageMgr.StatusBitmaps[StatusConstans.online];
				statusMenu.Append(online, new wx.EventListener(OnOnlineStatusClicked));
	
				wx.MenuItem away = new wx.MenuItem();
				away.Text = ContactManager.StatusToString(StatusConstans.away);
				away.Bitmap = mainFrame.ImageMgr.StatusBitmaps[StatusConstans.away];
				statusMenu.Append(away, new wx.EventListener(OnAwayStatusClicked));

				wx.MenuItem invisible = new wx.MenuItem();
				invisible.Text = ContactManager.StatusToString(StatusConstans.invisible);
				invisible.Bitmap = mainFrame.ImageMgr.StatusBitmaps[StatusConstans.invisible];
				statusMenu.Append(invisible, new wx.EventListener(OnInvisibleStatusClicked));
	
				wx.MenuItem offline = new wx.MenuItem();
				offline.Text = ContactManager.StatusToString(StatusConstans.offline);
				offline.Bitmap = mainFrame.ImageMgr.StatusBitmaps[StatusConstans.offline];
				statusMenu.Append(offline, new wx.EventListener(OnOfflineStatusClicked));
			}
			
			// setting panel color
			SetPanelColors();
			// setting font properties
			SetPanelFonts();
		}
		private void DoLayout()
		{
			wx.BoxSizer mainSizer = new wx.BoxSizer(wx.Orientation.wxVERTICAL);
			{
				topSizer = new wx.BoxSizer(wx.Orientation.wxVERTICAL);
				{
					topSizer.Add(new wx.StaticLine(this, wx.Window.wxDefaultPosition, wx.Window.wxDefaultSize, wx.StaticLine.wxLI_HORIZONTAL),
					             0, wx.Stretch.wxEXPAND);
					wx.BoxSizer infoSizer = new wx.BoxSizer(wx.Orientation.wxHORIZONTAL);
					{
						infoSizer.Add(photoBitmap, 0, wx.Alignment.wxALIGN_CENTER_HORIZONTAL);
						
						wx.BoxSizer textSizer = new wx.BoxSizer(wx.Orientation.wxVERTICAL);
						{
							textSizer.Add(contactNameText, 1, wx.Stretch.wxEXPAND, 0);
							textSizer.Add(contactDescriptionText, 2, wx.Stretch.wxEXPAND|wx.Direction.wxBOTTOM, 5);
						}
						infoSizer.Add(textSizer, 1, wx.Stretch.wxEXPAND|wx.Direction.wxLEFT, 5);
					}
					topSizer.Add(infoSizer, 1, wx.Stretch.wxEXPAND|wx.Direction.wxTOP, 5);
									
					topSizer.Add(new wx.StaticLine(this, wx.Window.wxDefaultPosition, wx.Window.wxDefaultSize, wx.StaticLine.wxLI_HORIZONTAL),
					             0, wx.Stretch.wxEXPAND|wx.Direction.wxBOTTOM, 5);
					topSizer.Add(descriptionBox, 0, wx.Stretch.wxEXPAND);
					topSizer.Add(statusBitmap, 0, wx.Alignment.wxALIGN_LEFT|wx.Direction.wxTOP, 5);
				}
				mainSizer.Add(topSizer, 1, wx.Stretch.wxEXPAND|wx.Direction.wxALL, 5);
			}
			this.Sizer = mainSizer;
			mainSizer.SetSizeHints(this);
			mainSizer.Fit(this);
		}
		
		/// <summary>
		/// Deletes all entries in description combo box.
		/// </summary>
		/// <remarks>
		/// Should be used with <c>EVT_UPDATE_UI</c> event
		/// to access description combo from other threads.
		/// </remarks>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="evt">
		/// A <see cref="wx.Event"/>
		/// </param>
		public void ClearDescriptionCombo(object sender, wx.Event evt)
		{
			descriptionBox.Clear();
			descriptionBox.Value = string.Empty;
		}

		private void OnStatusBitmapClicked(object sender)
		{		
			//FIXME: there is some error with PopupMenu, when it's
			//poped for the first time, clicking on menu item don't
			//trigger event
			//update: fixed by changes in wx.Window class code
			this.PopupMenu(statusMenu, statusBitmap.Position);
		}

		private void OnOnlineStatusClicked(object sender, wx.Event evt)
		{
		 	mainFrame.LaunchStatusChangeEvent(StatusConstans.online);
		}

		private void OnAwayStatusClicked(object sender, wx.Event evt)
		{
			mainFrame.LaunchStatusChangeEvent(StatusConstans.away);
		}

		private void OnOfflineStatusClicked(object sender, wx.Event evt)
		{
			mainFrame.LaunchStatusChangeEvent(StatusConstans.offline);
		}

		private void OnInvisibleStatusClicked(object sender, wx.Event evt)
		{
			mainFrame.LaunchStatusChangeEvent(StatusConstans.invisible);
		}

		/// <summary>
		///  Invoked when user select existing description from combo box
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="evt">
		/// A <see cref="wx.Event"/>
		/// </param>
		private void OnDescriptionSelected(object sender, wx.Event evt)
		{
			if (mainFrame.Dispatch.DescriptionMgr is DescriptionManager)
			{
				if (descriptionBox.Selection >= 0)
					mainFrame.Dispatch.DescriptionMgr.MoveUpDescription(descriptionBox.Selection);
				else
				{
#if LOG
					logger.Warn(Catalog.GetString("Selected description position value is < 0, this should not happen"));				
#endif
				}
			}
			else
			{
				mainFrame.Dispatch.Gadu.GGDescription = descriptionBox.Value;
			}
		}
		
		/// <summary>
		/// Invoked when user add new description to combo box
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="evt">
		/// A <see cref="wx.Event"/>
		/// </param>
		private void 	OnNewDescriptionAdded(object sender, wx.Event evt)
		{
			if (mainFrame.Dispatch.DescriptionMgr is DescriptionManager)
			{
				mainFrame.Dispatch.DescriptionMgr.AddDescription(descriptionBox.Value);
			}
			else
			{
				mainFrame.Dispatch.Gadu.GGDescription = descriptionBox.Value;
			}
		}
		
		private void OnDescriptionTextValueChanged(object sender, wx.Event evt)
		{
			if (descriptionBox.Value.Length >= 70)
			{
				descriptionBox.Value = descriptionBox.Value.Substring(0, 70);
				wx.Utils.Bell();
#if LOG
				logger.Trace(Catalog.GetString("Max description length has been reached"));
#endif
			}
		}
		
		
		/// <summary>
		/// Displays contact name, uin and photo on panel
		/// </summary>
		/// <param name="uin">
		/// A <see cref="System.Int32"/>
		/// Uin of contact that exist in <c>ContactManager.Contacts</c>
		/// list.
		/// </param>
		/// <remarks>
		/// <c>uin</c> value equal 0 means that panel should be cleared.
		/// </remarks>
		public void DisplayContactInfo(int uin)
		{
			if (!mainFrame.Dispatch.ContactMgr.Contacts.ContainsKey(uin))
			{
#if LOG
				logger.Trace(Catalog.GetString("ContactManager.Contacts list doesn't contain specified UIN, panel will be cleared"));
#endif
				contactDescriptionText.Value = string.Empty;
				contactNameText.Value = string.Empty;
				photoBitmap.Bitmap = mainFrame.ImageMgr[ImageManager.EMPTY];
				visibleUin = 0;
			}
			else
			{
#if LOG
				logger.Trace(String.Format(Catalog.GetString("Displaying info about UIN: {0}"), uin));
#endif
				ContactInfo ci = mainFrame.Dispatch.ContactMgr.Contacts[uin];
				contactDescriptionText.Value = ci.Description;
				contactNameText.Value = String.Format("{0}\n[{1}]", ci.Name, ci.Uin);
				if (ci.PhotoSmall == null)
				{
					string path = mainFrame.AppCfg.AvatarsDir + Path.DirectorySeparatorChar + ci.Uin + ".jpg";
					if (File.Exists(path))
					{
						try
						{
							wx.Bitmap avatar = new wx.Bitmap(Helper.LoadAndScale(path, 80));
							ci.PhotoSmall = avatar;
						}
						catch (ArgumentException)
						{ 
							ci.PhotoSmall = new wx.Bitmap(Helper.LoadAndScale(mainFrame.ImageMgr[ImageManager.NOBODY].ConvertToImage() , 80));
						}
					}
					else
					{
						ci.PhotoSmall = new wx.Bitmap(Helper.LoadAndScale(mainFrame.ImageMgr[ImageManager.NOBODY].ConvertToImage() , 80));
					}
				}
				photoBitmap.Bitmap = ci.PhotoSmall;
				visibleUin = ci.Uin;
			}
		}

		//// <value>
		/// This bitmap represents clickable current user status icon 
		/// in left down corner of main frame.
		/// </value>
		public wx.StaticBitmap StatusBitmap
		{
			get { return statusBitmap;	 }
		}
		
		//// <value>
		/// Widget that displays selected contact name and uin
		/// </value>
		public wx.TextCtrl ContactNameText
		{
			get { return contactNameText; }	
		}
		
		//// <value>
		/// Widget that displays selected contact description
		/// </value>
		public wx.TextCtrl ContactDescriptionText
		{
			get { return contactDescriptionText; }
		}
		
		//// <value>
		/// Widget that displays selected contact photo (avatar)
		/// </value>
		public wx.StaticBitmap PhotoBitmap
		{
			get { return photoBitmap; }
		}
		
		//// <value>
		/// Uin of contact which infos are curently displayed
		/// </value>
		public int VisibleUin
		{
			get { return visibleUin; }
		}
		
		private void SetPanelFonts()
		{
			wx.Font descFont, nameFont;
			if (mainFrame.AppCfg.UserConf.InfoPanelFont != null)
			{
				descFont = (wx.Font) mainFrame.AppCfg.UserConf.InfoPanelFont;
				nameFont = (wx.Font) mainFrame.AppCfg.UserConf.InfoPanelFont;
			}
			else
			{
				descFont = wx.SystemSettings.GetFont(wx.SystemFont.wxSYS_DEFAULT_GUI_FONT);
				nameFont = wx.SystemSettings.GetFont(wx.SystemFont.wxSYS_DEFAULT_GUI_FONT);
				descFont.PointSize -= 1;
				nameFont.PointSize -= 1;
			}
			nameFont.Weight = wx.FontWeight.wxBOLD;
			contactDescriptionText.Font = descFont;
			contactNameText.Font = nameFont;
		}
		
		private void SetPanelColors()
		{
			if (mainFrame.AppCfg.UserConf.InfoPanelBackground != null)
				this.BackgroundColour = (wx.Colour) mainFrame.AppCfg.UserConf.InfoPanelBackground;
			else
				this.BackgroundColour = wx.SystemSettings.GetColour(wx.SystemColour.wxSYS_COLOUR_BACKGROUND);
			
			contactDescriptionText.BackgroundColour = this.BackgroundColour;
			contactNameText.BackgroundColour = this.BackgroundColour;
		}
		
		private void OnInfoPanelClear(object sender, wx.Event evt)
		{
			photoBitmap.Bitmap = mainFrame.ImageMgr[ImageManager.EMPTY];
			contactDescriptionText.Value = string.Empty;
			contactNameText.Value = string.Empty;
			
			visibleUin = 0;
		}
		
		public void ClearInfoPanel()
		{
			this.EventHandler.AddPendingEvent(new wx.UpdateUIEvent((int) FakeId.clearInfoPanel));
		}
		
		public void UpdatePanelFonts(object sender, wx.Event evt)
		{
			SetPanelFonts();
		}
		
		public void UpdatePanelColors(object sender, wx.Event evt)
		{
			SetPanelColors();
		}
		
		public void PanelFontChanged(object sender)
		{
			this.EventHandler.AddPendingEvent(new wx.UpdateUIEvent((int) FakeId.infoPanelFontsChanged));
		}
		
		public void PanelColorChanged(object sender)
		{
			this.EventHandler.AddPendingEvent(new wx.UpdateUIEvent((int) FakeId.infoPanelColorChanged));
		}
		
		public wx.ComboBox UserDescriptionCombo
		{
			get { return descriptionBox; }
		}

	}
}
